﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using Microsoft.BizTalk.Streaming;
using Microsoft.Practices.ESB.Exception.Management;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.Practices.ESB.Resolver.BRE;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.XLANGs.BaseTypes;
using System.Xml;
using Microsoft.RuleEngine;
using BizTalk.ESB.Extensions.Helpers;

namespace BizTalk.ESB.Extensions.Resolvers
{
    public class StaticPropertyPromoterResolver : IResolveProvider
    {
        public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
        {
            // Create instance of PropertyPromoterResolution
            PropertyPromoterResolution propResolution = new PropertyPromoterResolution();
            var msg = (XmlDocument)message[0].RetrieveAs(typeof(XmlDocument));

            // Call ResolveStatic
            return ResolveStatic(resolverInfo.Config, resolverInfo.Resolver, propResolution, msg);
        }

        public Dictionary<string, string> Resolve(string config, string resolver, XmlDocument message)
        {
            // Create instance of PropertyPromoterResolution
            PropertyPromoterResolution propResolution = new PropertyPromoterResolution();

            // Call ResolveStatic
            return ResolveStatic(config, resolver, propResolution, message);
        }

        public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
        {
            Dictionary<string, string> resolverDictionary;
            // Create instance of PropertyPromoterResolution
            PropertyPromoterResolution propResolution = new PropertyPromoterResolution();
            var msg = new XmlDocument();
            try
            {
                if (message.BodyPart != null)
                {
                    Stream originalDataStream = message.BodyPart.GetOriginalDataStream();
                    if (!originalDataStream.CanSeek)
                    {
                        ReadOnlySeekableStream s = new ReadOnlySeekableStream(originalDataStream);
                        message.BodyPart.Data = s;
                        pipelineContext.ResourceTracker.AddResource(s);
                        originalDataStream = s;
                    }

                    if (originalDataStream.Position != 0L)
                    {
                        originalDataStream.Position = 0L;
                    }

                    msg.Load(originalDataStream);
                    originalDataStream.Position = 0L;
                    resolverDictionary = ResolveStatic(config, resolver, propResolution, msg);
                }
                else
                {
                    resolverDictionary = new Dictionary<string, string>();
                }
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (propResolution != null)
                {
                    propResolution = null;
                }
            }

            // Call ResolveStatic
            return resolverDictionary;
        }

        private static Dictionary<String, String> ResolveStatic(String config, String resolver, PropertyPromoterResolution resolution
            , XmlDocument message)
        {
            // DEBUG
            System.Diagnostics.Trace.WriteLine("CONFIG = " + config);
            System.Diagnostics.Trace.WriteLine("RESOLVER = " + resolver);

            Dictionary<String, String> resolverInfo = new Dictionary<String, String>();
            Dictionary<String, String> resolverDictionary = new Dictionary<String, String>();
            Dictionary<String, String> facts = null;

            if (!resolver.Contains(@":\"))
            {
                resolver = resolver + @":\";
            }
            try
            {
                facts = ResolverMgr.GetFacts(config, resolver);
                resolution.PropertyPromotionConfig = ResolverMgr.GetConfigValue(facts, true, "PropertyPromotionConfig");
                PropertyPromoterResolutionManager.SetResolverDictionary(resolution, resolverDictionary);
                resolverInfo = resolverDictionary;
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (facts != null)
                {
                    facts.Clear();
                    facts = null;
                }
                if (resolution != null)
                {
                    resolution = null;
                }
                if (resolverDictionary != null)
                {
                    resolverDictionary = null;
                }
            }

            return resolverInfo;
        }
    }

    //public class BrePropertyPromoterResolver : IResolveProvider
    //{
    //    public Dictionary<string,string> ResolverEsbConfig { get; set; }

    //    public BreBamTrackingResolver(Microsoft.Practices.ESB.Configuration.Resolver resolverConfig)
    //    {
    //        if (resolverConfig == null)
    //        {
    //            throw new ArgumentNullException("resolverConfig");
    //        }
    //        ResolverEsbConfig = new Dictionary<string, string>();
    //        ResolverEsbConfig.Add("Resolver.BAMConnectionString", ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "BAMPrimaryImportConnectionString"));
    //        ResolverEsbConfig.Add("Resolver.MsgBoxConnectionString", ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "MessageBoxConnectionString"));
    //        ResolverEsbConfig.Add("Resolver.Timeout", ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "Timeout"));
    //    }

    //    public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
    //    {
    //        // Create instance of ContextResolution
    //        Resolution ctxResolution = new Resolution();
    //        ResolverMgr.SetContext(ctxResolution, message);

    //        Dictionary<String, String> resolverDictionary;

    //        // Create instance of BamTrackingResolution
    //        var bamResolution = new BamTrackingResolution();

    //        // Create instance of BRE
    //        var breInfo = BamTrackingResolutionManager.CreateResolverDescriptor(resolverInfo.Config, resolverInfo.Resolver);

    //        try
    //        {
    //            if (breInfo.useMsg && breInfo.recognizeMessageFormat)
    //            {
    //                throw new ResolveException("Recognize Message Format not supported.");
    //            }

    //            BamTrackingResolutionManager.SetContext(bamResolution, message);
    //            XmlDocument msg = null;
    //            if (breInfo.useMsg)
    //            {
    //                msg = (XmlDocument)message[0].RetrieveAs(typeof(XmlDocument));
    //            }
    //            resolverDictionary = ResolveRules(resolverInfo.Config, resolverInfo.Resolver, bamResolution
    //                , msg, ResolverEsbConfig, breInfo, ctxResolution);
    //        }
    //        catch (Exception e)
    //        {
    //            EventLogger.Write(MethodBase.GetCurrentMethod(), e);
    //            throw;
    //        }
    //        finally
    //        {
    //            if (bamResolution != null)
    //            {
    //                bamResolution = null;
    //            }
    //        }

    //        return resolverDictionary;
    //    }

    //    public Dictionary<string, string> Resolve(string config, string resolver, XmlDocument message)
    //    {
    //        // Create instance of ContextResolution
    //        Resolution ctxResolution = new Resolution();

    //        Dictionary<string, string> resolverDictionary;

    //        // Create instance of BamTrackingResolution
    //        var bamResolution = new BamTrackingResolution();

    //        // Create instance of BRE
    //        var breInfo = BamTrackingResolutionManager.CreateResolverDescriptor(config, resolver);

    //        try
    //        {
    //            if (breInfo.useMsg && breInfo.recognizeMessageFormat)
    //            {
    //                throw new ResolveException("Recognize Message Format not supported.");
    //            }
    //            resolverDictionary = ResolveRules(config, resolver, bamResolution, message, ResolverEsbConfig, breInfo, ctxResolution);
    //        }
    //        catch (Exception e)
    //        {
    //            EventLogger.Write(MethodBase.GetCurrentMethod(), e);
    //            throw;
    //        }
    //        finally
    //        {
    //            if (bamResolution != null)
    //            {
    //                bamResolution = null;
    //            }
    //        }

    //        return resolverDictionary;
    //    }

    //    public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
    //    {
    //        // Create instance of ContextResolution
    //        Resolution ctxResolution = new Resolution();
    //        ResolverMgr.SetContext(ctxResolution, message, pipelineContext);

    //        Dictionary<string, string> resolverDictionary;

    //        // Create instance of BamTrackingResolution
    //        var bamResolution = new BamTrackingResolution();

    //        // Create instance of BRE
    //        var breInfo = BamTrackingResolutionManager.CreateResolverDescriptor(config, resolver);

    //        // Get Message
    //        XmlDocument msg = new XmlDocument();
    //        try
    //        {
    //            if (breInfo.useMsg && message.BodyPart != null)
    //            {
    //                Stream originalDataStream = message.BodyPart.GetOriginalDataStream();
    //                if (!originalDataStream.CanSeek)
    //                {
    //                    ReadOnlySeekableStream s = new ReadOnlySeekableStream(originalDataStream);
    //                    message.BodyPart.Data = s;
    //                    pipelineContext.ResourceTracker.AddResource(s);
    //                    originalDataStream = s;
    //                }

    //                if (originalDataStream.Position != 0L)
    //                {
    //                    originalDataStream.Position = 0L;
    //                }

    //                msg.Load(originalDataStream);
    //                originalDataStream.Position = 0L;
    //            }
    //            resolverDictionary = ResolveRules(config, resolver, bamResolution, msg, ResolverEsbConfig, breInfo, ctxResolution);
    //        }
    //        catch (Exception e)
    //        {
    //            EventLogger.Write(MethodBase.GetCurrentMethod(), e);
    //            throw;
    //        }
    //        finally
    //        {
    //            if (bamResolution != null)
    //            {
    //                bamResolution = null;
    //            }
    //        }

    //        return resolverDictionary;
    //    }

    //    private static Dictionary<String, String> ResolveRules(string config, string resolver, BamTrackingResolution resolution
    //        , XmlDocument message, Dictionary<string, string> resolverConfig, BRE breInfo, Resolution context)
    //    {
    //        // DEBUG
    //        System.Diagnostics.Trace.WriteLine("CONFIG = " + config);
    //        System.Diagnostics.Trace.WriteLine("RESOLVER = " + resolver);

    //        Dictionary<string, string> resolverInfo = new Dictionary<string, string>();
    //        Dictionary<string, string> resolverDictionary = new Dictionary<string, string>();
    //        Dictionary<string, string> facts = null;

    //        Int16 PolicyMajorVersion = 0;
    //        Int16 PolicyMinorVersion = 0;
    //        string[] VersionArray = null;
    //        Object[] policyFacts = null;
    //        Policy brePolicy = null;
    //        TypedXmlDocument xmlMsgForBre = null;
    //        string DocType = "Microsoft.Practices.ESB.ResolveProviderMessage";

    //        if (!resolver.Contains(@":\"))
    //        {
    //            resolver = resolver + @":\";
    //        }
    //        try
    //        {
    //            EventLogger.Write("Resolution strong name is {0}", new object[] { resolution.DocumentSpecStrongName });

    //            // Set the Doc Type
    //            if (String.IsNullOrEmpty(resolution.DocumentSpecStrongName) == false && breInfo.recognizeMessageFormat)
    //            {
    //                Int32 index = resolution.DocumentSpecStrongName.IndexOf(",", StringComparison.CurrentCultureIgnoreCase);
    //                if ((index > 0) && (index < resolution.DocumentSpecStrongName.Length))
    //                {
    //                    DocType = resolution.DocumentSpecStrongName.Substring(0, index);
    //                }
    //                else
    //                {
    //                    DocType = resolution.DocumentSpecStrongName;
    //                }
    //            }
    //            EventLogger.Write("DocType for typed xml document is {0}", new object[] { DocType });

    //            if (String.IsNullOrEmpty(breInfo.version) == false)
    //            {
    //                VersionArray = breInfo.version.Split(".".ToCharArray());
    //                if (VersionArray != null)
    //                {
    //                    PolicyMajorVersion = Convert.ToInt16(VersionArray[0], System.Globalization.NumberFormatInfo.CurrentInfo);
    //                    PolicyMinorVersion = Convert.ToInt16(VersionArray[1], System.Globalization.NumberFormatInfo.CurrentInfo);
    //                }
    //            }

    //            if (breInfo.useMsg)
    //            {
    //                policyFacts = new Object[3];
    //                xmlMsgForBre = new TypedXmlDocument(DocType, message);
    //                policyFacts[0] = resolution;
    //                policyFacts[1] = xmlMsgForBre;
    //                policyFacts[2] = context;
    //            }
    //            else
    //            {
    //                policyFacts = new Object[2];
    //                policyFacts[0] =  resolution;
    //                policyFacts[1] = context;
    //            }

    //            if (PolicyMajorVersion > 0)
    //            {
    //                brePolicy = new Policy(breInfo.policy, PolicyMajorVersion, PolicyMinorVersion);
    //            }
    //            else
    //            {
    //                brePolicy = new Policy(breInfo.policy);
    //            }

    //            brePolicy.Execute(policyFacts);
    //            brePolicy.Dispose();
    //            if (policyFacts[0] == null)
    //            {
    //                throw new ResolveException("Error executing BRE Resolver");
    //            }

    //            resolution = (BamTrackingResolution)policyFacts[0];
    //            BamTrackingResolutionManager.SetResolverDictionary(resolution, resolverDictionary);
    //            foreach (var configItem in resolverConfig)
    //            {
    //                resolverDictionary.Add(configItem.Key, configItem.Value);
    //            }
    //            resolverInfo = resolverDictionary;
    //        }
    //        catch (Exception e)
    //        {
    //            EventLogger.Write(MethodBase.GetCurrentMethod(), e);
    //            throw;
    //        }
    //        finally
    //        {
    //            if (facts != null)
    //            {
    //                facts.Clear();
    //                facts = null;
    //            }
    //            if (resolution != null)
    //            {
    //                resolution = null;
    //            }
    //            if (resolverDictionary != null)
    //            {
    //                resolverDictionary = null;
    //            }
    //        }

    //        return resolverInfo;
    //    }
    //}
}
